package com.budwk.app.sys.services.impl;

import com.budwk.app.common.config.AppException;
import com.budwk.app.sys.models.Sys_area;
import com.budwk.app.sys.services.SysAreaService;
import com.budwk.starter.common.constant.RedisConstant;
import com.budwk.starter.common.result.ResultCode;
import com.budwk.starter.database.service.BaseServiceImpl;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.nutz.aop.interceptor.async.Async;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.impl.NutTxDao;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.sql.SqlCallback;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.plugins.wkcache.annotation.CacheDefaults;
import org.nutz.plugins.wkcache.annotation.CacheRemoveAll;
import org.nutz.plugins.wkcache.annotation.CacheResult;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author wizzer.cn
 */
@IocBean(args = {"refer:dao"})
@CacheDefaults(cacheName = RedisConstant.WKCACHE + "shequ.sys_area", isHash = false, cacheLiveTime = RedisConstant.WKCACHE_TIMEOUT)
public class SysAreaServiceImpl extends BaseServiceImpl<Sys_area> implements SysAreaService {
    public SysAreaServiceImpl(Dao dao) {
        super(dao);
    }

    @Override
    @CacheResult
    public List<Sys_area> getSubListByCode(String code) {
        if (Strings.isNotBlank(code)) {
            Sys_area dict = this.fetch(Cnd.where("code", "=", code));
            return dict == null ? new ArrayList<>() : this.query(Cnd.where("parentId", "=", Strings.sNull(dict.getId())).asc("location"));
        } else {
            return this.query(Cnd.where("parentId", "=", "").asc("location"));
        }
    }

    @Override
    @CacheResult
    public NutMap getSubMapByCode(String code) {
        if (Strings.isNotBlank(code)) {
            Sys_area dict = this.fetch(Cnd.where("code", "=", code));
            return dict == null ? NutMap.NEW() : this.getNutMap(Sqls.create("select code,name from shequ.sys_area where parentId = @id order by location asc").setParam("id", dict.getId()));
        } else {
            return this.getNutMap(Sqls.create("select code,name from shequ.sys_area where parentId = '' order by location asc"));
        }
    }

    @Override
    @Aop(TransAop.READ_COMMITTED)
    public void save(Sys_area area, String pid) {
        String path = "";
        if (!Strings.isEmpty(pid)) {
            Sys_area pp = this.fetch(pid);
            path = pp.getPath();
        }
        area.setPath(getSubPath("sys_area", "path", path));
        area.setParentId(pid);
        dao().insert(area);
        if (!Strings.isEmpty(pid)) {
            this.update(Chain.make("hasChildren", true), Cnd.where("id", "=", pid));
        }
    }

    @Override
    @Aop(TransAop.READ_COMMITTED)
    public void deleteAndChild(Sys_area area) {
        dao().execute(Sqls.create("delete from shequ.sys_area where path like @path").setParam("path", area.getPath() + "%"));
        if (!Strings.isEmpty(area.getParentId())) {
            int count = count(Cnd.where("parentId", "=", area.getParentId()));
            if (count < 1) {
                dao().execute(Sqls.create("update shequ.sys_area set hasChildren=0 where id=@pid").setParam("pid", area.getParentId()));
            }
        }
    }

    @Override
    @CacheRemoveAll
    @Async
    public void cacheClear() {

    }

    @Override
    @CacheResult
    public String getAreaIdByName(String name) {
        Cnd cnd = Cnd.NEW();
        cnd.and(Sys_area::getName, "=", name);
        Sys_area sysArea = fetch(cnd);
        return sysArea.getId();
    }

    @Override
    @CacheResult
    public List<Sys_area> getSameLevelArea(String id, String name) {
        if (StringUtils.isEmpty(id) && StringUtils.isEmpty(name)) {
            throw new AppException(ResultCode.PARAM_ERROR.getMsg());
        }
        Cnd cnd = Cnd.NEW();
        cnd.and(Sys_area::getId, "=", id).or(Sys_area::getName, "=", name);
        Sys_area sysArea = fetch(cnd);

        Cnd aNew = Cnd.NEW();
        aNew.and(Sys_area::getParentId, "=", sysArea.getParentId());
        return query(aNew);
    }

    /**
     *     "name": "白云区",
     *     "areaFlag": 2
     *     清洗白云区所有街道
     *
     *     "name": "白云区",
     *     "areaFlag": 3
     *     清洗白云区下社区
     * @param name
     * @param areaFlag
     * @return
     */
    @Override
    @CacheRemoveAll
    public Integer batchInsert(String name, Integer areaFlag) {
        Cnd cnd = Cnd.NEW();
        cnd.and(Sys_area::getName, "=", name);
        Sys_area sysArea = fetch(cnd);
        if (ObjectUtils.isEmpty(sysArea)) {
            throw new AppException(ResultCode.NULL_DATA_ERROR.getMsg());
        }
        Sql sql = Sqls.create("select name, code from shequ.\"sys_area\" where parentId =@id");
        sql.setParam("id", sysArea.getId());
        sql.setCallback(new SqlCallback() {
            @Override
            public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {
                ResultSetMetaData metaData = rs.getMetaData();
                int columnCount = metaData.getColumnCount();
                List<Sys_area> resultList = new ArrayList<Sys_area>();
                while (rs.next()) {
                    Sys_area result = new Sys_area();
                    for (int i = 0; i < columnCount; i++) {
                        result.setName(rs.getString("name"));
                        result.setCode(rs.getString("code"));
                        result.setParentId(sysArea.getId());
                    }
                    resultList.add(result);
                }
                return resultList;
            }
        });
        this.execute(sql);
        List<Sys_area> sysAreas = sql.getList(Sys_area.class);
        if (sysAreas.size() == 0) {
            return 0;
        }
        Integer areaFlag2 = areaFlag + 1;
        Integer areaFlag3 = areaFlag + 2;
        sysAreas.forEach(itemParent -> {
            // 省
            List<Sys_area> sysAre1 = getAreaInfo(itemParent.getName(), areaFlag2);
            // 查询数据是否存在，不存在则插入
            for (Sys_area sysarea : sysAre1) {
                Cnd cnd1 = Cnd.NEW();
                cnd1.and(Sys_area::getParentId, "=", sysarea.getParentId()).and(Sys_area::getName, "=", sysarea.getName());
                if(count(cnd1) > 0 ) {
                    continue;
                }
                this.insert(sysarea);
            }
        });
        return 0;
    }

    private List<Sys_area> getAreaInfo(String name, Integer areaFlag) {
        // 先查询code对应的area信息
        Cnd cnd = Cnd.NEW();
        cnd.and("name", "=", name);
        Sys_area sysArea = fetch(cnd);
        if (ObjectUtils.isEmpty(sysArea)) {
            return null;
        }
        String code = sysArea.getCode();
        String sqlStr = "";
        switch (areaFlag) {
            // 知道省名称，迁移市数据
            case 1:
                sqlStr = "select name, city_code AS code from shequ.\"sys_area_20231106_guizhou\" where province_code = @code and city_code is not null and area_code is null and street_code is null and committee_code is null;";
                code = code.substring(0, 2);
                break;
            // 知道市名称，迁移区数据
            case 2:
                sqlStr = "select name, area_code AS code  from shequ.\"sys_area_20231106_guizhou\"  where city_code = @code and city_code is not null and area_code is not null and street_code is null and committee_code is null";
                code = code.substring(0, 4);
                break;
            // 知道区名称，迁移街道数据
            case 3:
                sqlStr = "select name, street_code AS code  from shequ.\"sys_area_20231106_guizhou\"  where area_code = @code  and city_code is not null and area_code is not null and street_code is not null and committee_code is null";
                code = code.substring(0, 6);
                break;
            // 知道街道名称，迁移社区数据
            case 4:
                sqlStr = "select name, committee_code AS code  from shequ.\"sys_area_20231106_guizhou\"  where street_code = @code  and city_code is not null and area_code is not null and street_code is not null and committee_code is not null";
                break;
        }
        Sql sql = Sqls.create(sqlStr);
        sql.setParam("code", code);
        sql.setCallback(new SqlCallback() {
            @Override
            public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {
                ResultSetMetaData metaData = rs.getMetaData();
                int columnCount = metaData.getColumnCount();
                List<Sys_area> resultList = new ArrayList<Sys_area>();
                while (rs.next()) {
                    Sys_area result = new Sys_area();
                    for (int i = 0; i < columnCount; i++) {
                        result.setName(rs.getString("name"));
                        result.setCode(rs.getString("code"));
                        result.setParentId(sysArea.getId());
                    }
                    resultList.add(result);
                }
                return resultList;
            }
        });
        this.execute(sql);
        return sql.getList(Sys_area.class);
    }
}
